import pygame
import sys
from typing import Dict, Any, List, Tuple, Optional
import json
import os

# 定义颜色常量
class Colors:
    BLACK = (0, 0, 0)
    WHITE = (255, 255, 255)
    GRAY = (200, 200, 200)
    LIGHT_GRAY = (230, 230, 230)
    DARK_GRAY = (100, 100, 100)
    BLUE = (0, 120, 255)
    RED = (255, 0, 0)
    GREEN = (0, 200, 0)
    DARK_BG = (40, 44, 52)  # 深色背景
    DARKER_BG = (30, 34, 42)  # 更深的背景色
    BUTTON_BLUE = (61, 90, 254)  # 蓝色按钮
    BUTTON_HOVER = (94, 114, 235)  # 悬停时的按钮颜色
    ACCENT = (255, 165, 0)  # 强调色（橙色）

# 默认参数配置
DEFAULT_PARAMS = {
    "交通系统": {
        "move_cooldown": 0.5,
        "vehicle_spawn_rate": 0.2,
        "max_vehicles": 50
    },
    "道路": {
        "capacity": 100,
        "default_speed_limit": 2.0
    },
    "交通灯": {
        "cycle_time": 60,
        "green_time": 30,
        "yellow_time": 5
    },
    "车辆": {
        "default_speed": 1.0,
        "acceleration": 0.1,
        "deceleration": 0.2
    }
}

class Button:
    def __init__(self, x: int, y: int, width: int, height: int, text: str, 
                 color: Tuple[int, int, int] = Colors.BLUE,
                 text_color: Tuple[int, int, int] = Colors.WHITE,
                 hover_color: Tuple[int, int, int] = None):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.color = color
        self.text_color = text_color
        self.hover_color = hover_color or (min(color[0] + 30, 255), min(color[1] + 30, 255), min(color[2] + 30, 255))
        self.is_hovered = False
        
    def draw(self, screen, font):
        # 绘制按钮背景
        color = self.hover_color if self.is_hovered else self.color
        pygame.draw.rect(screen, color, self.rect, border_radius=5)
        pygame.draw.rect(screen, Colors.DARK_GRAY, self.rect, 2, border_radius=5)
        
        # 绘制按钮文本
        text_surface = font.render(self.text, True, self.text_color)
        text_rect = text_surface.get_rect(center=self.rect.center)
        screen.blit(text_surface, text_rect)
        
    def check_hover(self, mouse_pos):
        self.is_hovered = self.rect.collidepoint(mouse_pos)
        return self.is_hovered
        
    def is_clicked(self, mouse_pos, mouse_clicked):
        return self.rect.collidepoint(mouse_pos) and mouse_clicked

class InputField:
    def __init__(self, x: int, y: int, width: int, height: int, 
                 initial_value: str = "", label: str = "",
                 numeric_only: bool = False):
        self.rect = pygame.Rect(x, y, width, height)
        self.value = str(initial_value)
        self.label = label
        self.active = False
        self.numeric_only = numeric_only
        self.label_width = 150  # 标签宽度
        
    def draw(self, screen, font):
        # 绘制标签
        if self.label:
            label_surface = font.render(self.label, True, Colors.WHITE)
            screen.blit(label_surface, (self.rect.x - self.label_width, self.rect.y + 5))
        
        # 绘制输入框
        border_color = Colors.BUTTON_BLUE if self.active else (80, 84, 92)
        bg_color = (60, 64, 72) if not self.active else (70, 74, 82)
        
        # 绘制输入框背景
        pygame.draw.rect(screen, bg_color, self.rect, border_radius=5)
        pygame.draw.rect(screen, border_color, self.rect, 2, border_radius=5)
        
        # 绘制文本
        text_surface = font.render(self.value, True, Colors.WHITE)
        screen.blit(text_surface, (self.rect.x + 5, self.rect.y + 5))
        
        # 如果活动状态，绘制光标
        if self.active and pygame.time.get_ticks() % 1000 < 500:
            text_width = font.size(self.value)[0]
            cursor_x = self.rect.x + 5 + text_width
            pygame.draw.line(screen, Colors.WHITE, 
                            (cursor_x, self.rect.y + 5), 
                            (cursor_x, self.rect.y + self.rect.height - 5), 2)
    
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            self.active = self.rect.collidepoint(event.pos)
        
        if event.type == pygame.KEYDOWN and self.active:
            if event.key == pygame.K_BACKSPACE:
                self.value = self.value[:-1]
            elif event.key == pygame.K_RETURN:
                self.active = False
            else:
                # 如果是数字输入模式，只接受数字和小数点
                if self.numeric_only:
                    if event.unicode.isdigit() or (event.unicode == '.' and '.' not in self.value):
                        self.value += event.unicode
                else:
                    self.value += event.unicode
            return True
        return False

class ParametersManager:
    def __init__(self, width: int = 800, height: int = 700):
        pygame.init()
        self.width = width
        self.height = height
        self.screen = pygame.display.set_mode((width, height))
        pygame.display.set_caption("路径规划系统参数设置")
        
        # 字体设置
        try:
            self.font = pygame.font.SysFont("microsoftyahei", 18)
            self.title_font = pygame.font.SysFont("microsoftyahei", 24, bold=True)
        except:
            try:
                self.font = pygame.font.SysFont("simsun", 18)
                self.title_font = pygame.font.SysFont("simsun", 24, bold=True)
            except:
                print("警告：未找到中文字体，使用默认字体")
                self.font = pygame.font.Font(None, 18)
                self.title_font = pygame.font.Font(None, 24)
        
        # 加载参数
        self.params = self.load_params()
        
        # 当前选中的分类
        self.current_category = list(self.params.keys())[0]
        
        # 创建UI元素
        self.create_ui_elements()
        
        # 创建按钮 - 稍微提高按钮位置
        self.save_button = Button(width - 220, height - 80, 100, 40, "保存", Colors.GREEN)
        self.reset_button = Button(width - 110, height - 80, 100, 40, "重置", Colors.RED)
        self.back_button = Button(20, height - 80, 100, 40, "返回主页", Colors.BLUE)
        
    def create_ui_elements(self):
        self.category_buttons = []
        x = 20
        for i, category in enumerate(self.params.keys()):
            btn = Button(x, 20, 120, 40, category)
            self.category_buttons.append(btn)
            x += 130
        
        # 创建输入字段
        self.update_input_fields()
    
    def update_input_fields(self):
        self.input_fields = []
        y = 100
        for param_name, value in self.params[self.current_category].items():
            input_field = InputField(200, y, 150, 30, value, param_name, numeric_only=True)
            self.input_fields.append(input_field)
            y += 40
    
    def load_params(self) -> Dict[str, Dict[str, Any]]:
        """从文件加载参数，如果文件不存在则使用默认参数"""
        if os.path.exists("traffic_params.json"):
            try:
                with open("traffic_params.json", "r", encoding="utf-8") as f:
                    return json.load(f)
            except:
                print("加载参数文件失败，使用默认参数")
                return DEFAULT_PARAMS.copy()
        else:
            return DEFAULT_PARAMS.copy()
    
    def save_params(self):
        """保存参数到文件"""
        # 更新参数值
        for field in self.input_fields:
            try:
                # 尝试转换为数值类型
                if '.' in field.value:
                    value = float(field.value)
                else:
                    value = int(field.value)
                self.params[self.current_category][field.label] = value
            except ValueError:
                # 如果转换失败，保持原值
                print(f"无效的数值: {field.value}，保持原值")
        
        # 保存到文件
        with open("traffic_params.json", "w", encoding="utf-8") as f:
            json.dump(self.params, f, ensure_ascii=False, indent=4)
        
        print("参数已保存")
    
    def reset_params(self):
        """重置为默认参数"""
        self.params = DEFAULT_PARAMS.copy()
        self.update_input_fields()
    
    def run(self):
        """运行参数设置界面"""
        running = True
        clock = pygame.time.Clock()
        result = self.params  # 默认返回参数
        
        while running:
            mouse_pos = pygame.mouse.get_pos()
            mouse_clicked = False
            
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                if event.type == pygame.MOUSEBUTTONDOWN:
                    mouse_clicked = True
                
                # 处理输入字段事件
                for field in self.input_fields:
                    field.handle_event(event)
            
            # 检查按钮悬停和点击
            for i, btn in enumerate(self.category_buttons):
                btn.check_hover(mouse_pos)
                if btn.is_clicked(mouse_pos, mouse_clicked):
                    # 保存当前分类的参数
                    self.save_params()
                    # 切换分类
                    self.current_category = list(self.params.keys())[i]
                    self.update_input_fields()
            
            # 检查保存和重置按钮
            self.save_button.check_hover(mouse_pos)
            self.reset_button.check_hover(mouse_pos)
            self.back_button.check_hover(mouse_pos)
            
            if self.save_button.is_clicked(mouse_pos, mouse_clicked):
                self.save_params()
            
            if self.reset_button.is_clicked(mouse_pos, mouse_clicked):
                self.reset_params()
                
            if self.back_button.is_clicked(mouse_pos, mouse_clicked):
                # 在返回前保存参数
                self.save_params()
                result = "back_to_main"  # 返回特殊标记，表示要返回主菜单
                running = False
            
            # 绘制界面
            self.draw()
            
            pygame.display.flip()
            clock.tick(60)
        
        # 不要在这里调用pygame.quit()，让主程序负责初始化和退出
        # pygame.quit()
        return result
    
    def draw(self):
        """绘制界面"""
        # 填充深色背景
        self.screen.fill(Colors.DARK_BG)
        
        # 绘制网格背景
        grid_color = (50, 54, 62)  # 网格线颜色
        for x in range(0, self.width, 20):
            pygame.draw.line(self.screen, grid_color, (x, 0), (x, self.height))
        for y in range(0, self.height, 20):
            pygame.draw.line(self.screen, grid_color, (0, y), (self.width, y))
        
        # 绘制标题区域
        title_bg = pygame.Rect(0, 0, self.width, 60)
        pygame.draw.rect(self.screen, Colors.DARKER_BG, title_bg)
        
        # 绘制标题
        title = self.title_font.render("路径规划系统参数设置", True, Colors.WHITE)
        self.screen.blit(title, (self.width // 2 - title.get_width() // 2, 15))
        
        # 绘制装饰线
        pygame.draw.line(self.screen, Colors.ACCENT, 
                       (self.width // 2 - 100, 45), 
                       (self.width // 2 + 100, 45), 3)
        
        # 绘制分类按钮
        for i, btn in enumerate(self.category_buttons):
            # 高亮当前选中的分类
            if list(self.params.keys())[i] == self.current_category:
                btn.color = Colors.BUTTON_BLUE
                btn.hover_color = Colors.BUTTON_HOVER
            else:
                btn.color = Colors.DARK_GRAY
                btn.hover_color = (min(Colors.DARK_GRAY[0] + 30, 255), min(Colors.DARK_GRAY[1] + 30, 255), min(Colors.DARK_GRAY[2] + 30, 255))
            btn.draw(self.screen, self.font)
        
        # 绘制当前分类标题和装饰线
        category_title = self.title_font.render(f"{self.current_category}参数", True, Colors.WHITE)
        self.screen.blit(category_title, (20, 70))
        pygame.draw.line(self.screen, Colors.BUTTON_BLUE, (20, 100), (200, 100), 2)
        
        # 绘制输入字段背景面板 - 缩小面板高度，为底部区域留出空间
        panel_bg = pygame.Rect(10, 110, self.width - 20, self.height - 200)
        pygame.draw.rect(self.screen, Colors.DARKER_BG, panel_bg, border_radius=10)
        pygame.draw.rect(self.screen, grid_color, panel_bg, 1, border_radius=10)
        
        # 绘制输入字段
        for field in self.input_fields:
            field.draw(self.screen, self.font)
        
        # 绘制保存和重置按钮
        self.save_button.color = Colors.GREEN
        self.save_button.text_color = Colors.WHITE
        self.save_button.draw(self.screen, self.font)
        
        self.reset_button.color = Colors.RED
        self.reset_button.text_color = Colors.WHITE
        self.reset_button.draw(self.screen, self.font)
        
        # 绘制返回按钮
        self.back_button.color = Colors.BUTTON_BLUE
        self.back_button.text_color = Colors.WHITE
        
        # 添加悬停效果
        mouse_pos = pygame.mouse.get_pos()
        if self.back_button.rect.collidepoint(mouse_pos):
            self.back_button.color = Colors.BUTTON_HOVER
            # 添加左侧指示器
            indicator_rect = pygame.Rect(self.back_button.rect.x - 10, 
                                       self.back_button.rect.y + self.back_button.rect.height // 2 - 8, 
                                       5, 16)
            pygame.draw.rect(self.screen, Colors.ACCENT, indicator_rect, border_radius=2)
        
        self.back_button.draw(self.screen, self.font)
        
        # 绘制说明 - 将说明放在按钮下方
        help_bg = pygame.Rect(10, self.height - 35, self.width - 20, 30)
        pygame.draw.rect(self.screen, Colors.DARKER_BG, help_bg, border_radius=5)
        help_text = self.font.render("提示：修改参数后点击保存按钮或切换分类自动保存", True, (200, 200, 200))
        self.screen.blit(help_text, (20, self.height - 30))

def get_params() -> Dict[str, Dict[str, Any]]:
    """获取参数，如果参数文件存在则加载，否则打开参数设置界面"""
    if os.path.exists("traffic_params.json"):
        try:
            with open("traffic_params.json", "r", encoding="utf-8") as f:
                return json.load(f)
        except:
            print("加载参数文件失败，打开参数设置界面")
            return open_params_window()
    else:
        return open_params_window()

def open_params_window() -> Dict[str, Dict[str, Any]]:
    """打开参数设置窗口"""
    # 暂存之前的显示模式
    old_surface = None
    if pygame.display.get_surface() is not None:
        old_surface = pygame.display.get_surface()
        old_size = old_surface.get_size()
        old_display_info = pygame.display.Info()
    
    params_manager = ParametersManager()
    result = params_manager.run()
    
    # 如果返回的是返回主菜单标记，则加载保存的参数并返回
    if result == "back_to_main":
        try:
            with open("traffic_params.json", "r", encoding="utf-8") as f:
                return json.load(f)
        except:
            print("加载参数文件失败，使用默认参数")
            return DEFAULT_PARAMS.copy()
    else:
        return result

if __name__ == "__main__":
    # 测试参数设置界面
    params = open_params_window()
    print("获取的参数:", params) 